use crate::{configuration, method_not_allowed, not_found};
use axum::{Router, middleware};
use log::{error, info};
use std::net::SocketAddr;
use tokio::net::TcpListener;
use tower::ServiceBuilder;

#[tokio::main]
pub async fn run(route: Router) {
    init().await;

    let route = route
        // 状态码为404时的回调方法
        .fallback(not_found)
        // 状态码为405时的回调方法
        .method_not_allowed_fallback(method_not_allowed);
    #[cfg(feature = "tower")]
    let builder = ServiceBuilder::new();
    #[cfg(feature = "trace")]
    let builder = builder.layer(crate::middleware::get_trace_layer());
    #[cfg(feature = "cors")]
    let builder = builder.layer(crate::middleware::get_cors_layer());
    #[cfg(feature = "auth")]
    let builder = builder.layer(crate::middleware::get_auth_layer());
    #[cfg(feature = "print")]
    let builder = builder
        .layer(middleware::from_fn(crate::middleware::print_request))
        /*.layer(middleware::from_fn(crate::middleware::print_response))*/;
    #[cfg(feature = "timeout")]
    let builder = builder.layer(crate::middleware::get_timeout_layer());
    // #[cfg(feature = "print")]
    // let builder = builder.layer(middleware::from_fn(crate::middleware::print_response));
    #[cfg(feature = "tower")]
    let route = route.layer(builder);

    let server = configuration::server();
    let address = format!("0.0.0.0:{}", server.port());
    info!("Listening on http://{}", address);
    let listener = TcpListener::bind(address).await;
    if let Err(e) = listener {
        error!("服务启动失败：{}", e);
        return;
    }

    let server = axum::serve(
        listener.unwrap(),
        route.into_make_service_with_connect_info::<SocketAddr>(),
    )
    .await;
    if let Err(e) = server {
        error!("服务启动失败：{}", e)
    }
}

/// 初始化日志、数据库、redis、amqp、定时任务
async fn init() {
    #[cfg(feature = "logger")]
    tracing_plus::init_tracing_log();
    #[cfg(feature = "database")]
    crate::db::get();
    #[cfg(feature = "redis")]
    crate::rediss::init();
    #[cfg(feature = "amqp")]
    crate::amqp::init();
    #[cfg(feature = "minio")]
    crate::minio::get();
    #[cfg(feature = "scheduler")]
    crate::scheduled::init_scheduler().await;
}
